/**
 * 
 */
package info.pixstone.foodhunter.apps.service;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Observable;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;

/**
 * @author MadStone
 * 
 */
public class FoodLocation extends Observable implements LocationListener {

	/*
	 * @see
	 * android.location.LocationListener#onLocationChanged(android.location.
	 * Location)
	 */

	private static LocationManager lmgr;
	private static Context mContext;
	private static String best;
	private static long minTime = 3000;
	private static int minDistance = 100;
	public static final String TAG = "FoodLocation";
	public static Location currentLocation = null;
	private static final String UPDATE_LOCATION_ACTION = "info.pixstone.foodhunter.apps.UPDATE_LOCATION_ACTION";
	private static Geocoder mGeocoder = null;
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	FoodLocation(Context context) {
		mContext = context;
		initLocationManager();
	}

	
	
	protected boolean isBetterLocation(Location location, Location currentBestLocation) {
	    if (currentBestLocation == null) {
	        // A new location is always better than no location
	        return true;
	    }

	    // Check whether the new location fix is newer or older
	    long timeDelta = location.getTime() - currentBestLocation.getTime();
	    boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
	    boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
	    boolean isNewer = timeDelta > 0;

	    // If it's been more than two minutes since the current location, use the new location
	    // because the user has likely moved
	    if (isSignificantlyNewer) {
	        return true;
	    // If the new location is more than two minutes older, it must be worse
	    } else if (isSignificantlyOlder) {
	        return false;
	    }

	    // Check whether the new location fix is more or less accurate
	    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
	    boolean isLessAccurate = accuracyDelta > 0;
	    boolean isMoreAccurate = accuracyDelta < 0;
	    boolean isSignificantlyLessAccurate = accuracyDelta > 200;

	    // Check if the old and new location are from the same provider
	    boolean isFromSameProvider = isSameProvider(location.getProvider(),
	            currentBestLocation.getProvider());

	    // Determine location quality using a combination of timeliness and accuracy
	    if (isMoreAccurate) {
	        return true;
	    } else if (isNewer && !isLessAccurate) {
	        return true;
	    } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
	        return true;
	    }
	    return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
	    if (provider1 == null) {
	      return provider2 == null;
	    }
	    return provider1.equals(provider2);
	}
	
	public static boolean isEnabled(Context context) {

		if (lmgr.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			return true;
		}
		if (lmgr.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
			return true;
		}
		return false;
	}

	public static void openLocationSetting(Activity act, int requestCode) {
		act.startActivityForResult(
				new Intent("ACTION_LOCATION_SOURCE_SETTINGS"), requestCode);
	}
	private static void enableLocationSettings() {
	    Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
	    mContext. startActivity(settingsIntent);
	}

	public String getBest() {
		if (lmgr == null) {
			initLocationManager();
		}
		return best;
	}

	private final void initLocationManager() {
		
		lmgr = (LocationManager) mContext
				.getSystemService(Context.LOCATION_SERVICE);
		 final boolean gpsEnabled = lmgr.isProviderEnabled(LocationManager.GPS_PROVIDER);

		    if (!gpsEnabled) {
		    	enableLocationSettings();
		    }
		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		criteria.setAltitudeRequired(false);
		criteria.setBearingRequired(false);
		criteria.setPowerRequirement(Criteria.POWER_LOW);
		criteria.setSpeedRequired(false);
		criteria.setCostAllowed(true);
		best = lmgr.getBestProvider(criteria, true);
		lmgr.requestLocationUpdates(best, minTime, minDistance, this);
		mGeocoder = new Geocoder(mContext, Locale.getDefault());
	}

	
	private static Handler handler = new Handler();

	public static final void getLocationHandler() {
		currentLocation = lmgr.getLastKnownLocation(best);
		if (currentLocation == null) {
			handler.post(new LocationRunnable(lmgr,best));
		}
		Intent intent = new Intent();
		intent.setAction(UPDATE_LOCATION_ACTION);
		intent.putExtra("Location",
				"Lat:" + currentLocation.getLatitude() + "Lat:"
						+ currentLocation.getLongitude());
		Log.d(TAG,"getLocationHandler");
		mContext.sendBroadcast(intent);

	}

	public static final void getAddressHandler(final Context mContext) {
		if (currentLocation != null) {
			handler.post(new Runnable() {
				public void run() {

					List<Address> addressList = null;
					try {
						while (addressList == null) {
							addressList = mGeocoder.getFromLocation(
									currentLocation.getLatitude(),
									currentLocation.getLongitude(), 5);

							this.wait(200);

						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					 if (addressList != null && addressList.size() > 0) {
				            Address address = addressList.get(0);
				            // Format the first line of address (if available), city, and country name.
				            String addressText = String.format("%s, %s, %s",
				                    address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(0) : "",
				                    address.getLocality(),
				                    address.getCountryName());
					Intent intent = new Intent();
					intent.setAction(UPDATE_LOCATION_ACTION);
					intent.putExtra("Location", addressText + " ");
					mContext.sendBroadcast(intent);
				}
				}

			});
		}
	}

	public void onLocationChanged(Location location) {
		setChanged();
		notifyObservers(location);
		Log.d(TAG, "Changed");
	}

	/*
	 * @see
	 * android.location.LocationListener#onProviderDisabled(java.lang.String)
	 */
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub
		enableLocationSettings();
	}

	/*
	 * @see
	 * android.location.LocationListener#onProviderEnabled(java.lang.String)
	 */
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub
	}

	/*
	 * @see android.location.LocationListener#onStatusChanged(java.lang.String,
	 * int, android.os.Bundle)
	 */
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
	}


}
